#include "tcpclient.h"
#include "ui_tcpclient.h"
#include <QByteArray> //字节数组，文件读取的返回值
#include <QDebug> //用于打印
#include <QMessageBox> //报错窗口
#include <QHostAddress> //用于此对象
#include"privatechat.h"

/**
 * @brief 默认构造函数
 * @param parent
 */
TcpClient::TcpClient(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::TcpClient)
{
    ui->setupUi(this);
    resize(500,300);

    //加载配置文件，产生socket信号
    loadConfig();

    //连接槽和服务器的信号  信号发送放、信号内容、接收方、处理函数
    connect(&m_tcpSocket, SIGNAL(connected()), this,SLOT(showConnect()));
    //有数据进入，实现recvMsg()接收
    connect(&m_tcpSocket, SIGNAL(readyRead()), this,SLOT(recvMsg()));

    m_tcpSocket.connectToHost(QHostAddress(m_strIP),m_usPort); //使用socket连接服务器
}

TcpClient::~TcpClient()
{
    delete ui;
}

/**
 * @brief 加载配置信息
 */
void TcpClient::loadConfig()
{
    QFile file(":/client.config"); //加载配置文件
    if(file.open(QIODevice::ReadOnly)){ //QIODevice为编写模式的作用域，返回值bool
        QByteArray baData = file.readAll(); //以字节数组形式返回
        QString strData = baData.toStdString().c_str(); //类型转化
        file.close();

        //数据处理
        strData.replace("\r\n"," "); //替换\r\n
        QStringList strList=strData.split(" "); //以空格切分出字符串列表
        m_strIP = strList.at(0);
        m_usPort = strList.at(1).toUShort();
        qDebug() << "ip:" << m_strIP << " port:" << m_usPort;
    }
    else{
        QMessageBox::critical(this,"open config","open config failed"); //报错--打开配置文件
    }
}

TcpClient &TcpClient::getInstance()
{
    static TcpClient instance;
    return instance;
}

QTcpSocket &TcpClient::getTcpSocket()
{
    return m_tcpSocket;
}

QString TcpClient::loginName()
{
    return m_strLoginName;
}

QString TcpClient::curPath()
{
    return m_strCurPath;
}

void TcpClient::setCurPath(QString strCurPath){
    m_strCurPath=strCurPath;
}

/**
 * @brief 显示连接情况
 */
void TcpClient::showConnect()
{
    QMessageBox::information(this,"连接服务器","连接服务器成功");
}

void TcpClient::recvMsg()
{
    if(!OpeWidget::getInstance().getBook()->getDownloadFlag()){
        qDebug()<<m_tcpSocket.bytesAvailable();   //输出数据总长12+64+x
        uint uiPUDLen=0;
        m_tcpSocket.read((char*)&uiPUDLen,sizeof(uint));  //获取uiPDULen
        uint uiMsgLen=uiPUDLen-sizeof(PDU); //解析实际动态数组的长度
        PDU *pdu=mkPDU(uiMsgLen); //为PDU开辟空间
        m_tcpSocket.read((char*)pdu+sizeof (uint),uiPUDLen-sizeof(uint));  //接收剩余信息并填充
    //    qDebug()<<pdu->uiMsgType<<(char*)(pdu->caMsg);  //输出传来的uiMsgType，还有数据
        //判断消息类型
        switch (pdu->uiMsgType) {
            //注册请求的回复
        case ENUM_MSG_TYPE_REGIST_RESPOND:{
            if(strcmp(pdu->caData,REGIST_OK)==0){
                QMessageBox::information(this,"注册",REGIST_OK);
            }
            else if(strcmp(pdu->caData,REGIST_FAILED)==0){
                QMessageBox::warning(this,"注册",REGIST_FAILED);
            }
            break;
        }
            //登录请求的回复
        case ENUM_MSG_TYPE_LOGIN_RESPOND:{
            if(strcmp(pdu->caData,LOGIN_OK)==0){
                //登录成功 操作用户目录
                QString str1="D:/work/demo/demo1-v1/book/";
                QString str2=QString("%1").arg(m_strLoginName);
                m_strCurPath=QString(str1.append((str2)));
                QMessageBox::information(this,"注册",LOGIN_OK);
                //登录成功后，由操作界面的对象，切换到界面
                OpeWidget::getInstance().show();
                this->hide();   //this表示登录界面
            }
            else if(strcmp(pdu->caData,LOGIN_FAILED)==0){
                QMessageBox::warning(this,"注册",LOGIN_FAILED);
            }
            break;
        }
            //显示在线用户的回复
        case ENUM_MSG_TYPE_ALL_ONLINE_RESPOND:{
            OpeWidget::getInstance().getFriend()->showAllOnlineUsr(pdu);
            break;
        }
            //搜索用户的回复
        case ENUM_MSG_TYPE_SEARCH_USR_RESPOND:{
            //用户不存在
            if(strcmp(SEARCH_USR_NO,pdu->caData)==0){
                QMessageBox::information(this,"搜索",QString("%1: not exist").arg(OpeWidget::getInstance().getFriend()->m_strSeachName));
            }
            //用户在线
            else if(strcmp(SEARCH_USR_ONLINE,pdu->caData)==0){
                QMessageBox::information(this,"搜索",QString("%1: online").arg(OpeWidget::getInstance().getFriend()->m_strSeachName));
            }
            //用户不在线
            else if(strcmp(SEARCH_USR_OFFLINE,pdu->caData)==0){
                QMessageBox::information(this,"搜索",QString("%1: offline").arg(OpeWidget::getInstance().getFriend()->m_strSeachName));
            }
            break;
        }
            //已转发好友申请
        case ENUM_MSG_TYPE_ADD_FRIEND_REQUEST:{
            char caName[32]={'\0'};
            strncpy(caName,pdu->caData+32,32);
            int ret=QMessageBox::information(this,"添加好友",QString("%1 want to add you as friend ?").arg(caName)
                                     ,QMessageBox::Yes,QMessageBox::No);
            PDU *respdu=mkPDU(0);
            //添加对方的名字 及 请求者的名字
            memcpy(respdu->caData,pdu->caData,64);
            if(ret==QMessageBox::Yes){
                //同意添加好友
                respdu->uiMsgType=ENUM_MSG_TYPE_ADD_FRIEND_AGREE;
            }
            else if(ret==QMessageBox::No){
                //不同意添加好友
                respdu->uiMsgType=ENUM_MSG_TYPE_ADD_FRIEND_REFUSE;
            }
            //数据处理后发送给服务器
            m_tcpSocket.write((char*)respdu,pdu->uiPDULen);
            free(respdu);
            respdu=NULL;
            break;
        }
            //好友申请回复
        case ENUM_MSG_TYPE_ADD_FRIEND_RESPOND:{
            QMessageBox::information(this,"添加好友",pdu->caData);
            break;
        }
            //显示添加成功
        case ENUM_MSG_TYPE_ADD_FRIEND_AGREE:
        {
            char caPerName[32] = {'\0'};
            memcpy(caPerName, pdu->caData, 32);
            QMessageBox::information(this, "添加好友", QString("添加%1好友成功").arg(caPerName));
            break;
        }
            //显示添加失败
        case ENUM_MSG_TYPE_ADD_FRIEND_REFUSE:
        {
            char caPerName[32] = {'\0'};
            memcpy(caPerName, pdu->caData, 32);
            QMessageBox::information(this, "添加好友", QString("添加%1好友失败").arg(caPerName));
            break;
        }
            //刷新好友回复
        case ENUM_MSG_TYPE_FLUSH_FRIEND_RESPOND:{
            OpeWidget::getInstance().getFriend()->updateFriendList(pdu);
            break;
        }
            //告知对方删除好友
        case ENUM_MSG_TYPE_DELETE_FRIEND_REQUEST:{
            char caName[32]={'\0'};
            memcpy(caName,pdu->caData,32);
            QMessageBox::information(this, "删除好友", QString("%1 删除你作为他的好友").arg(caName));
            break;
        }
            //回复请求者
        case ENUM_MSG_TYPE_DELETE_FRIEND_RESPOND:{
            QMessageBox::information(this, "删除好友", "删除好友成功");
            break;
        }
            //收到转发的私聊请求
        case ENUM_MSG_TYPE_PRIVATE_CHAT_REQUEST:{
            if(PrivateChat::getInstance().isHidden()){
                PrivateChat::getInstance().show();
            }
            char caSendName[32]={'\0'};
            memcpy(caSendName,pdu->caData,32);
            //在弹出的窗口中包含对方的名字
            PrivateChat::getInstance().setChatName(caSendName);
            PrivateChat::getInstance().updateMsg(pdu);
            break;
        }
            //收到转发的群聊消息
        case ENUM_MSG_TYPE_GROUP_CHAT_REQUEST:{
            //friend更新窗口
            OpeWidget::getInstance().getFriend()->updateGroupMsg(pdu);
            break;
        }
            //收到创建目录的回复
        case ENUM_MSG_TYPE_CREATE_DIR_RESPOND:{
            QMessageBox::information(this,"创建文件",pdu->caData);
            break;
        }
            //收到刷新目录的回复
        case ENUM_MSG_TYPE_FLUSH_FILE_RESPOND:{
            OpeWidget::getInstance().getBook()->updateFileList(pdu);
            QString strEnterDir = OpeWidget::getInstance().getBook()->enterDir();
            if (!strEnterDir.isEmpty())
            {
                m_strCurPath = m_strCurPath+"/"+strEnterDir;
                qDebug() << "enter dir:" << m_strCurPath;
            }
            break;
        }
            //收到删除文件目录的回复
        case ENUM_MSG_TYPE_DEL_DIR_RESPOND:{
            QMessageBox::information(this,"删除文件夹",pdu->caData);
            break;
        }
            //收到重命名文件的回复
        case ENUM_MSG_TYPE_RENAME_FILE_RESPOND:{
            QMessageBox::information(this,"重命名文件",pdu->caData);
            break;
        }
            //收到进入文件夹的回复
        case ENUM_MSG_TYPE_ENTER_DIR_RESPOND:{
            OpeWidget::getInstance().getBook()->clearEnterDir();
            QMessageBox::information(this,"进入文件夹",pdu->caData);
            break;
        }
            //收到上传文件的回复
        case ENUM_MSG_TYPE_UPLOAD_FILE_RESPOND:{
            QMessageBox::information(this,"上传文件",pdu->caData);
            break;
        }
            //收到删除常规文件的回复
        case ENUM_MSG_TYPE_DEL_FILE_RESPOND:{
            QMessageBox::information(this,"删除文件",pdu->caData);
            break;
        }
            //收到下载的回复
        case ENUM_MSG_TYPE_DOWNLOAD_FILE_RESPOND:{
            //caData返回要下载的文件名 文件大小
            qDebug()<<pdu->caData;
            char caFileName[32]={'\0'};
            //因为是输入？所以要取地址
            sscanf(pdu->caData,"%s %lld",caFileName,&(OpeWidget::getInstance().getBook()->m_iTotal));
            if(strlen(caFileName)>0&&OpeWidget::getInstance().getBook()->m_iTotal>0){
                OpeWidget::getInstance().getBook()->setDownloadFlag(true);
                m_file.setFileName(OpeWidget::getInstance().getBook()->getSaveFilePath());
                if(!m_file.open(QIODevice::WriteOnly)){
                    QMessageBox::warning(this,"下载文件","获得下载的文件失败");
                }
            }

            break;
        }
            //共享文件回复
        case ENUM_MSG_TYPE_SHARE_FILE_RESPOND:{
            QMessageBox::information(this,"共享文件",pdu->caData);
            break;
        }
            //共享文件通知
        case ENUM_MSG_TYPE_SHARE_FILE_NOTE:{
            char *pPath =new char[pdu->uiMsgLen];
            memcpy(pPath,pdu->caMsg,pdu->uiMsgLen);
            //从后往前找指定字符
            char *pos=strrchr(pPath,'/');
            if(pos!=NULL){
                pos++;
                QString strNote=QString("%1 share file->%2 \n Do you accept？").arg(pdu->caData).arg(pos);
                int ret=QMessageBox::question(this,"共享文件",strNote);
                if(QMessageBox::Yes==ret){
                    PDU *respdu=mkPDU(pdu->uiMsgLen);
                    //设置消息类型，caMsg放入路径
                    respdu->uiMsgType=ENUM_MSG_TYPE_SHARE_FILE_NOTE_RESPOND;
                    memcpy(respdu->caMsg,pdu->caMsg,pdu->uiMsgLen);
                    //放入客户端名字
                    QString strName=TcpClient::getInstance().loginName();
                    strcpy(respdu->caData,strName.toStdString().c_str());
                    m_tcpSocket.write((char*)respdu,respdu->uiPDULen);
                    free(respdu);
                    respdu=NULL;
                }
            }
            break;
        }
            //移动文件回复
        case ENUM_MSG_TYPE_MOVE_FILE_RESPOND:{
            qDebug()<<pdu->caData<<1;
            QMessageBox::information(this,"移动文件",pdu->caData);
            break;
        }
        default:
            break;
        }

        free(pdu);
        pdu=NULL;
    }
    else{
        //数据接受
        QByteArray buffer=m_tcpSocket.readAll();
        m_file.write(buffer);
        Book *pBook=OpeWidget::getInstance().getBook();
        pBook->m_iRecved+=buffer.size();
        if(pBook->m_iTotal==pBook->m_iRecved){  //下载完成
            m_file.close();
            pBook->m_iTotal=0;
            pBook->m_iRecved=0;
            pBook->setDownloadFlag(false);
            QMessageBox::information(this,"下载文件","下载文件成功");
        }
        else if(pBook->m_iTotal<pBook->m_iRecved){  //收到的数据更大
            m_file.close();
            pBook->m_iTotal=0;
            pBook->m_iRecved=0;
            pBook->setDownloadFlag(false);

            QMessageBox::critical(this,"下载文件","下载文件失败");
        }
    }
}

//void TcpClient::on_send_pb_clicked()
//{
//    QString strMsg=ui->lineEdit->text();    //从控件获取消息
//    if(!strMsg.isEmpty()){
//        PDU *pdu=mkPDU(strMsg.size()+1);
//        pdu->uiMsgType=8888;    //测试用参
//        memcpy(pdu->caMsg,strMsg.toStdString().c_str(),strMsg.size());
//        qDebug()<<(char*)(pdu->caMsg);  //输出客户端输入的数据
//        m_tcpSocket.write((char*)pdu,pdu->uiPDULen);    //利用Tcp协议发送数据
//        free(pdu);
//        pdu=NULL;
//    }
//    else{
//        QMessageBox::warning(this,"信息发送","发送的信息不能为空");
//    }
//}

void TcpClient::on_login_pb_clicked()
{
    QString strName=ui->name_le->text();
    QString strPwd=ui->pwd_le->text();
    if(!strName.isEmpty()&&!strPwd.isEmpty()){
        m_strLoginName = strName;
        PDU *pdu=mkPDU(0);  //前面部分不用到，消息写0
        pdu->uiMsgType=ENUM_MSG_TYPE_LOGIN_REQUEST;
        //前32字节放用户名，后面32字节放密码
        strncpy(pdu->caData,strName.toStdString().c_str(),32);
        strncpy(pdu->caData+32,strPwd.toStdString().c_str(),32);
        m_tcpSocket.write((char*)pdu,pdu->uiPDULen);    //利用Tcp协议发送数据
        free(pdu);
        pdu=NULL;
    }
    else{
        QMessageBox::critical(this,"登录","登录失败：用户名或者密码为空");
    }
}

void TcpClient::on_regist_pb_clicked()
{
    QString strName=ui->name_le->text();
    QString strPwd=ui->pwd_le->text();
    //账号和密码都已设置，发送注册请求
    if(!strName.isEmpty()&&!strPwd.isEmpty()){
        PDU *pdu=mkPDU(0);  //前面部分不用到，消息写0
        pdu->uiMsgType=ENUM_MSG_TYPE_REGIST_REQUEST;
        //前32字节放用户名，后面32字节放密码
        strncpy(pdu->caData,strName.toStdString().c_str(),32);
        strncpy(pdu->caData+32,strPwd.toStdString().c_str(),32);
        m_tcpSocket.write((char*)pdu,pdu->uiPDULen);    //利用Tcp协议发送数据
        free(pdu);
        pdu=NULL;
    }
    else{
        QMessageBox::critical(this,"注册","注册失败：用户名或者密码为空");
    }
}

void TcpClient::on_cancle_pb_clicked()
{

}
